有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java中与互斥体相关的多线程问题

我试图理解多线程编程的概念。我知道死锁和互斥锁的概念,但我找不到以下问题的答案。当使用互斥锁时,死锁问题是如何产生的


共 (2) 个答案

  1. # 1 楼答案

    互斥是同步块的关键。不正确使用synchronized block/mutex变量会导致死锁

  2. # 2 楼答案

    下面是一个如何在Java中激发deadlock的具体示例。我们产生两个线程。第一个获取a上的互斥锁,然后等待第二个,然后尝试获取b上的锁。第二个获取b上的锁,然后等待,然后尝试获取a。结果是程序进入死锁并永远运行

    public class Deadlock {
        public static void main(String[] args) {
            final Object a = new Object();
            final Object b = new Object();
            new Thread() {
                @Override
                public void run() {
                    synchronized (a) {
                        /* wait for a second to make it likely the other thread can acquire b */
                        try { Thread.sleep(1000); } catch (Exception e) {  }
                        synchronized (b) {
                            System.out.println("Acquired a, then b.");
                        }
                    }
                }
            }.start();
            new Thread() {
                @Override
                public void run() {
                    synchronized (b) {
                        /* wait for a second to make it likely the other thread can acquire a */
                        try { Thread.sleep(1000); } catch (Exception e) {  }
                        synchronized (a) {
                            System.out.println("Acquired b, then a.");
                        }
                    }
                }
            }.start();
        }
    }
    

    注意,这段代码不能保证进入死锁状态。线程调度程序完全有权在启动第二个线程之前运行第一个线程,或者反之亦然。由于本例中的大量等待时间,几乎可以肯定系统将进入死锁状态,但如果不是休眠一秒钟,而是在每次获取锁之前,两个线程都在进行可变时间长度的计算,则以下任何情况都可能随机发生:

    • 僵局
    • "Acquired a, then b.",然后是"Acquired b, then a."
    • "Acquired b, then a.",然后是"Acquired a, then b."

    如何防止这种情况发生

    • 只要你能逃脱惩罚,就不要完全使用线程
    • 与其在线程之间共享资源,不如让每个线程对自己的数据进行操作,并相互发送不可变的消息
    • 如果您必须使用共享资源,请尽量减少使用的互斥锁的数量。如果所有东西都在同一个对象上同步,那么只有一个互斥锁,死锁就不会发生
    • 如果你一定要有很多互斥锁,线程会获取它们的组合,那么请执行以下操作:编写一个函数,定义锁的总顺序。然后,每当需要执行涉及多个互斥体的操作时,创建所涉及互斥体的列表,对它们进行排序,然后在操作开始时按排序顺序输入它们

    看看java.util.concurrent包。里面有很多好吃的东西,可以照顾到很多真正毛茸茸的部分

    此外,我不能夸大线程在意外位置切换的程度。一个常见的错误是逐行查看每个线程,想象这些线程可以以不同的方式交错。但这还不够:一个线程可能会在某个库中某个嵌套函数调用的中间被切换出去。p>